#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
配置验证与错误处理模块
负责确保配置格式正确，提供友好的错误提示
"""

from typing import Dict, Any, List, Tuple
import re


class ConfigValidationError(Exception):
    """
    配置验证错误异常类
    提供更详细的配置错误信息
    """
    
    def __init__(self, message: str, errors: List[str] = None):
        """
        初始化配置验证错误
        
        Args:
            message: 错误消息
            errors: 详细错误列表
        """
        self.errors = errors or []
        super().__init__(self._format_message(message))
    
    def _format_message(self, message: str) -> str:
        """
        格式化错误消息
        
        Args:
            message: 基础错误消息
            
        Returns:
            格式化后的错误消息
        """
        if not self.errors:
            return message
        
        error_list = "\n".join([f"  - {error}" for error in self.errors])
        return f"{message}\n详细错误:\n{error_list}"


class ConfigValidator:
    """
    配置验证器
    提供全面的配置验证功能
    """
    
    def __init__(self):
        """
        初始化验证器
        """
        # 验证规则
        self._validation_rules = {
            'category_name': self._validate_category_name,
            'option_name': self._validate_option_name,
            'keywords': self._validate_keywords,
            'required_fields': self._validate_required_fields
        }
    
    def validate_config(self, config: Dict[str, Any]) -> Tuple[bool, List[str]]:
        """
        全面验证配置
        
        Args:
            config: 要验证的配置字典
            
        Returns:
            (是否有效, 错误信息列表)
        """
        errors = []
        
        # 检查配置是否为空
        if not config:
            errors.append("配置为空")
            return False, errors
        
        # 逐个验证每个规则
        for rule_name, validation_func in self._validation_rules.items():
            try:
                is_valid, rule_errors = validation_func(config)
                if not is_valid:
                    errors.extend(rule_errors)
            except Exception as e:
                errors.append(f"验证规则 '{rule_name}' 执行失败: {str(e)}")
        
        # 执行自定义验证逻辑
        custom_errors = self._custom_validations(config)
        if custom_errors:
            errors.extend(custom_errors)
        
        return len(errors) == 0, errors
    
    def validate_and_raise(self, config: Dict[str, Any]) -> None:
        """
        验证配置，如果无效则抛出异常
        
        Args:
            config: 要验证的配置字典
            
        Raises:
            ConfigValidationError: 配置验证失败时抛出
        """
        is_valid, errors = self.validate_config(config)
        if not is_valid:
            raise ConfigValidationError("配置验证失败", errors)
    
    def _validate_category_name(self, config: Dict[str, Any]) -> Tuple[bool, List[str]]:
        """
        验证类目名称
        
        Args:
            config: 配置字典
            
        Returns:
            (是否有效, 错误信息列表)
        """
        errors = []
        
        for category_name in config.keys():
            # 检查名称是否为空
            if not category_name or not category_name.strip():
                errors.append(f"类目名称不能为空")
                continue
            
            # 检查名称格式
            if not re.match(r'^[\u4e00-\u9fa5a-zA-Z0-9\s]+$', category_name):
                errors.append(f"类目名称 '{category_name}' 包含非法字符，只允许中文、英文、数字和空格")
        
        return len(errors) == 0, errors
    
    def _validate_option_name(self, config: Dict[str, Any]) -> Tuple[bool, List[str]]:
        """
        验证选项名称
        
        Args:
            config: 配置字典
            
        Returns:
            (是否有效, 错误信息列表)
        """
        errors = []
        
        for category_name, category_data in config.items():
            options = category_data.get('options', {})
            
            for option_name in options.keys():
                # 检查名称是否为空
                if not option_name or not option_name.strip():
                    errors.append(f"类目 '{category_name}' 中的选项名称不能为空")
                    continue
                
                # 检查名称格式
                if not re.match(r'^[\u4e00-\u9fa5a-zA-Z0-9\s]+$', option_name):
                    errors.append(f"类目 '{category_name}' 中的选项名称 '{option_name}' 包含非法字符，只允许中文、英文、数字和空格")
        
        return len(errors) == 0, errors
    
    def _validate_keywords(self, config: Dict[str, Any]) -> Tuple[bool, List[str]]:
        """
        验证关键词
        
        Args:
            config: 配置字典
            
        Returns:
            (是否有效, 错误信息列表)
        """
        errors = []
        
        for category_name, category_data in config.items():
            options = category_data.get('options', {})
            
            for option_name, option_data in options.items():
                keywords = option_data.get('keywords', [])
                
                # 检查关键词列表是否为空
                if not keywords:
                    errors.append(f"类目 '{category_name}' 的选项 '{option_name}' 缺少关键词")
                    continue
                
                # 检查每个关键词
                for keyword in keywords:
                    if not keyword or not keyword.strip():
                        errors.append(f"类目 '{category_name}' 的选项 '{option_name}' 包含空关键词")
                        continue
                    
                    # 检查关键词长度
                    if len(keyword) > 50:
                        errors.append(f"类目 '{category_name}' 的选项 '{option_name}' 中的关键词 '{keyword}' 过长（超过50个字符）")
        
        return len(errors) == 0, errors
    
    def _validate_required_fields(self, config: Dict[str, Any]) -> Tuple[bool, List[str]]:
        """
        验证必填字段
        
        Args:
            config: 配置字典
            
        Returns:
            (是否有效, 错误信息列表)
        """
        errors = []
        
        required_fields = ['description', 'required', 'options']
        
        for category_name, category_data in config.items():
            # 检查类目级必填字段
            for field in required_fields:
                if field not in category_data:
                    errors.append(f"类目 '{category_name}' 缺少必填字段 '{field}'")
            
            # 检查选项数据结构
            options = category_data.get('options', {})
            if not isinstance(options, dict):
                errors.append(f"类目 '{category_name}' 的 'options' 字段必须是字典类型")
                continue
            
            # 检查是否至少有一个选项
            if not options:
                errors.append(f"类目 '{category_name}' 至少需要一个选项")
            
            # 检查每个选项的数据结构
            for option_name, option_data in options.items():
                if not isinstance(option_data, dict):
                    errors.append(f"类目 '{category_name}' 的选项 '{option_name}' 数据必须是字典类型")
                    continue
                
                if 'keywords' not in option_data:
                    errors.append(f"类目 '{category_name}' 的选项 '{option_name}' 缺少 'keywords' 字段")
                elif not isinstance(option_data['keywords'], list):
                    errors.append(f"类目 '{category_name}' 的选项 '{option_name}' 的 'keywords' 字段必须是列表类型")
        
        return len(errors) == 0, errors
    
    def _custom_validations(self, config: Dict[str, Any]) -> List[str]:
        """
        自定义验证逻辑
        
        Args:
            config: 配置字典
            
        Returns:
            错误信息列表
        """
        errors = []
        
        # 检查类目数量合理性
        if len(config) > 50:
            errors.append(f"类目数量过多（{len(config)}个），建议不超过50个")
        
        # 检查每个类目的选项数量
        for category_name, category_data in config.items():
            options = category_data.get('options', {})
            if len(options) > 20:
                errors.append(f"类目 '{category_name}' 的选项数量过多（{len(options)}个），建议不超过20个")
            
            # 检查每个选项的关键词数量
            for option_name, option_data in options.items():
                keywords = option_data.get('keywords', [])
                if len(keywords) > 50:
                    errors.append(f"类目 '{category_name}' 的选项 '{option_name}' 的关键词数量过多（{len(keywords)}个），建议不超过50个")
        
        # 检查必填类目是否至少有一个
        required_count = sum(1 for data in config.values() if data.get('required', False))
        if required_count == 0:
            errors.append("配置中没有设置必填类目，建议至少设置一个必填类目")
        
        return errors
    
    def generate_validation_report(self, config: Dict[str, Any]) -> str:
        """
        生成验证报告
        
        Args:
            config: 要验证的配置字典
            
        Returns:
            验证报告文本
        """
        is_valid, errors = self.validate_config(config)
        
        report = ["配置验证报告", "=" * 50]
        
        # 配置基本信息
        report.append(f"类目总数: {len(config)}")
        report.append(f"必填类目数: {sum(1 for data in config.values() if data.get('required', False))}")
        
        # 详细统计
        option_count = 0
        keyword_count = 0
        
        for category_name, category_data in config.items():
            options = category_data.get('options', {})
            option_count += len(options)
            for option_data in options.values():
                keyword_count += len(option_data.get('keywords', []))
        
        report.append(f"选项总数: {option_count}")
        report.append(f"关键词总数: {keyword_count}")
        
        # 验证结果
        report.append("\n验证结果:")
        if is_valid:
            report.append("✅ 配置验证通过!")
        else:
            report.append(f"❌ 配置验证失败，发现 {len(errors)} 个问题:")
            for i, error in enumerate(errors, 1):
                report.append(f"  {i}. {error}")
        
        return "\n".join(report)


# 使用示例
if __name__ == '__main__':
    from .category_parser import CategoryConfigParser
    from .config_manager import CategoryConfigManager
    
    try:
        # 加载配置
        parser = CategoryConfigParser()
        manager = CategoryConfigManager()
        validator = ConfigValidator()
        
        print("加载配置文件...")
        config_path = "../../data/编码类目表.txt"
        
        # 首先使用解析器加载
        config = parser.parse_file(config_path)
        print(f"解析完成，共解析到 {len(config)} 个类目")
        
        # 生成详细验证报告
        print("\n生成配置验证报告...")
        report = validator.generate_validation_report(config)
        print(report)
        
        # 尝试严格验证（会抛出异常）
        print("\n执行严格验证...")
        validator.validate_and_raise(config)
        print("严格验证通过!")
        
        # 使用验证器进行配置管理
        print("\n使用验证器管理配置...")
        manager.load_config(config_path)  # 这会内部使用基本验证
        
        # 现在使用我们的高级验证器再次验证
        loaded_config = manager.get_config()
        is_valid, errors = validator.validate_config(loaded_config)
        
        print(f"\n高级验证结果: {'通过' if is_valid else '失败'}")
        if not is_valid:
            print("详细错误:")
            for error in errors:
                print(f"  - {error}")
        
        print("\n配置验证模块测试完成!")
        
    except ConfigValidationError as e:
        print(f"\n配置验证错误: {str(e)}")
    except Exception as e:
        print(f"\n测试失败: {str(e)}")